Migrate conversation language field default to 'en' - #11349
Conversation
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_5bc4e1a2-b781-4698-89cf-a72835462ac6) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3204027c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # Initialize Firebase Admin SDK | ||
| try: | ||
| cred = credentials.ApplicationDefault() | ||
| firebase_admin.initialize_app(cred) |
There was a problem hiding this comment.
Defer Firebase initialization until migration execution
Move Firebase initialization and firestore.client() into main() (and inject the client into the helpers). The required python backend/scripts/scan_import_time_side_effects.py check reports this new top-level firebase_admin.initialize_app call, so the commit cannot pass preflight; it also prevents importing the migration helpers without initializing credentialed infrastructure.
AGENTS.md reference: backend/AGENTS.md:L235-L235
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 8a6c13d: Firebase init and client construction are fully deferred; the migration calls database._client.get_firestore_client() only inside execution paths, and scan_import_time_side_effects.py reports 0 violations.
| except Exception as e: | ||
| logger.error(f"Error processing {uid}: {e}") |
There was a problem hiding this comment.
Fail the migration when any user update fails
If a Firestore read or batch commit fails for even one user, this handler only logs the exception and the process still prints Done and exits successfully. A transient failure or concurrent document deletion can therefore leave part of the database unmigrated while deployment automation or an operator records the migration as successful; track failures and return a nonzero exit status after all futures finish.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 8a6c13d: worker failures are counted and the process exits non-zero (sys.exit(1)), so automation cannot record a partial run as successful. Covered by test_worker_failure_exits_nonzero.
|
|
||
| source: Optional[ConversationSource] = ConversationSource.omi | ||
| language: Optional[str] = None # applies only to Friend # TODO: once released migrate db to default 'en' | ||
| language: Optional[str] = 'en' # applies only to Friend |
There was a problem hiding this comment.
Add regression coverage for the new language defaults
Add tests proving that omitted language values default to en for all three changed conversation models, and that the migration updates missing/empty values while preserving existing languages and exposing write failures. This commit changes production defaults and adds a data migration without modifying any test, contrary to the repository's required behavior-change coverage.
AGENTS.md reference: AGENTS.md:L28-L28
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed: test_conversation_language_default.py proves omitted language defaults to 'en' on all three models with explicit values preserved; test_migrate_language_to_en.py covers missing/empty backfill, existing-language preservation, dry-run, and failure exit.
|
|
||
| source: ConversationSource = ConversationSource.omi | ||
| language: Optional[str] = None | ||
| language: Optional[str] = 'en' |
There was a problem hiding this comment.
Preserve the detected language when creating sync conversations
The sync pipeline derives language from the user's explicit preference or STT detection, but constructs CreateConversation without passing it and supplies it only as the separate processing argument (utils/sync/pipeline.py:1075,1149-1162). With this new default, _get_conversation_obj serializes such Spanish or other non-English conversations as language='en'; subsequent reprocessing uses the persisted conversation.language, so summaries and derived data can be regenerated in English. Pass the resolved language into the model rather than allowing the default to replace a known value.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 02fb397: process_segment now passes the resolved language into CreateConversation, with regression test test_detected_language_is_stored_on_new_conversation (French-detected sync persists 'fr').
| # so we get all conversations and filter locally, or just check 'language' field. | ||
| # To be efficient, we'll stream conversations and update those needing it. | ||
|
|
||
| conversations = list(conversations_ref.stream()) |
There was a problem hiding this comment.
Stream projected conversation fields during the backfill
For users with long histories or large encrypted transcript documents, list(conversations_ref.stream()) downloads every field and retains the user's entire conversation history in memory; with 64 users processed concurrently, the production-wide migration can exhaust memory and transfer far more Firestore data than needed before it reaches the updates. Iterate the stream directly and project only language so memory remains bounded and transcript blobs are not fetched.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 8a6c13d: conversations are streamed with .select(['language']) only, no list() materialization; users are paged by document id so memory stays bounded.
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 3/5
- In
backend/models/conversation.py, defaultingCreateConversation.languageto'en'creates a concrete regression risk for callers that omit the field (such as the sync pipeline), which can silently store conversations with the wrong language and affect downstream language-dependent behavior—ensure detected/preferred language is always passed explicitly or remove the default and fail fast when missing.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/models/conversation.py">
<violation number="1" location="backend/models/conversation.py:289">
P1: With `CreateConversation.language` now defaulting to `'en'`, any caller that constructs `CreateConversation` without explicitly passing the detected/preferred language (e.g. the sync pipeline, which resolves language separately) will silently persist `language='en'` even for non-English conversations. Since `conversation.language` is used for later reprocessing, this can cause summaries and derived data to be regenerated in English for non-English conversations. Ensure all callers pass the resolved language into the model instead of relying on the new default.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
|
||
| source: ConversationSource = ConversationSource.omi | ||
| language: Optional[str] = None | ||
| language: Optional[str] = 'en' |
There was a problem hiding this comment.
P1: With CreateConversation.language now defaulting to 'en', any caller that constructs CreateConversation without explicitly passing the detected/preferred language (e.g. the sync pipeline, which resolves language separately) will silently persist language='en' even for non-English conversations. Since conversation.language is used for later reprocessing, this can cause summaries and derived data to be regenerated in English for non-English conversations. Ensure all callers pass the resolved language into the model instead of relying on the new default.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/models/conversation.py, line 289:
<comment>With `CreateConversation.language` now defaulting to `'en'`, any caller that constructs `CreateConversation` without explicitly passing the detected/preferred language (e.g. the sync pipeline, which resolves language separately) will silently persist `language='en'` even for non-English conversations. Since `conversation.language` is used for later reprocessing, this can cause summaries and derived data to be regenerated in English for non-English conversations. Ensure all callers pass the resolved language into the model instead of relying on the new default.</comment>
<file context>
@@ -286,7 +286,7 @@ class CreateConversation(BaseModel):
source: ConversationSource = ConversationSource.omi
- language: Optional[str] = None
+ language: Optional[str] = 'en'
processing_conversation_id: Optional[str] = None
</file context>
There was a problem hiding this comment.
Covered by the fix for 3746820357 (02fb397): the sync pipeline threads the detected/preferred language into CreateConversation and a non-English sync regression test asserts it.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_065eca9c-02b5-4d79-8b24-9ecf232bdd3d) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c3f793ddc9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| cred = credentials.ApplicationDefault() | ||
| firebase_admin.initialize_app(cred) |
There was a problem hiding this comment.
Use the shared Firestore client for migration credentials
When an operator uses the backend-supported SERVICE_ACCOUNT_JSON credential mode, credentials.ApplicationDefault() ignores that variable and the migration exits because it only accepts ADC via GOOGLE_APPLICATION_CREDENTIALS. Use database._client.get_firestore_client() so the migration honors the repository's credential preparation and configured Firestore target instead of requiring operators to translate supported credentials manually.
AGENTS.md reference: backend/AGENTS.md:L191-L193
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 8a6c13d: the migration uses database._client.get_firestore_client(), which routes through prepare_google_credentials and honors SERVICE_ACCOUNT_JSON.
undivisible
left a comment
There was a problem hiding this comment.
Changing the default language to en can silently rewrite non-English synced conversations because affected creation paths do not propagate detected language. Please preserve detected language for synced conversations, constrain the default to the intended Friend migration, and add regression coverage for a non-English sync.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_6603c84c-ab69-4c78-a529-414bf1e453fd) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1794dae771
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| for doc in conversations: | ||
| data = doc.to_dict() | ||
| if data.get('source') not in ('friend', 'friend_com'): |
There was a problem hiding this comment.
Backfill Omi-source conversations too
Historical sync-created conversations are stored with source omi: process_segment defaults its source to ConversationSource.omi, and before this commit its CreateConversation call omitted the language. This filter therefore skips exactly those existing records that can lack the field, leaving their persisted language unset even though the migration reports success. Include omi in the backfill scope rather than limiting it to the legacy Friend source names.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed: the migration applies to all conversation sources (no source filter), so omi-source sync conversations with missing language are backfilled too.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf7b0f620a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "backend/utils/retrieval/tools/calendar_tools.py": 1513, | ||
| "backend/utils/stt/streaming.py": 1523, | ||
| "backend/utils/sync/pipeline.py": 2499 | ||
| "backend/utils/sync/pipeline.py": 2500 |
There was a problem hiding this comment.
Restore the ratchet to the unchanged source count
Reset this entry to 2499 and remove the unrelated baseline raise. backend/utils/sync/pipeline.py is not modified by this commit and remains 2499 lines, so running check_product_file_line_count_ratchet.py against the commit reports both that the source file is absent from the diff and that the raised limit does not match its line count; this makes the required preflight contract fail.
AGENTS.md reference: AGENTS.md:L34-L35
Useful? React with 👍 / 👎.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_207e2a77-843a-4f14-8794-b66e7da92bf6) |
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for pushing this through — the backend/model default itself looks consistent, but I’m going to block until the migration/CI pieces are made safe and green.
Blocking items:
-
backend/migrations/008_migrate_language_to_en.pyis a production Firestore data migration, but it eagerly loads every user (get_all_users()returnslist(users_ref.stream())) and then eagerly loads every conversation for each user (conversations = list(conversations_ref.stream())) while running 64 users in parallel. For Omi-scale user data this has a high blast radius: unbounded memory/read load, no paging/checkpoint/resume, and no operator throttle beyond--dry-run. Please make this migration bounded and operationally safe before merge (stream or page users/conversations, lower/configure concurrency, include progress/checkpoint/resume or at least an explicit max-users/max-writes guard, and document the dry-run/rollout command). -
CI is currently red on this head.
Dart Analyze & Testsfails the analyzer ratchet withoverride_on_non_overriding_member: 5 found, baseline 0, whileHygiene/PR Metadata Preflightfailfailure-class-protocolbecause thefix:commits do not declareFailure-Class: FC-<slug> | new | none. Please fix the ratchet/generated-file state and the required failure-class declaration so the PR is mergeable.
File-specific notes from this review:
backend/models/conversation.py: the three Pydantic defaults now make omitted conversation language resolve toen; that matches the stated backend/API intent, but it makes the migration/rollout correctness more important because omitted values will no longer remain distinguishable from English.app/lib/backend/schema/gen/conversation_wire.g.dart: the generated client parser now also defaults missinglanguageto"en", which is consistent with the backend but should be regenerated/validated with the app analyzer green.backend/migrations/008_migrate_language_to_en.py: needs the production-safety changes above before it should be run against user conversation data.docs/api-reference/app-client-openapi.json: the two added OpenAPIdefault: "en"entries match the backend request/response schema change.docs/api-reference/integration-public-openapi.json: the public integration schema also reflects the new default; this is worth keeping because external clients may rely on the documented default.app/analysis_baseline.json: the baseline edit does not match the current analyzer result, so it needs to be corrected together with the generated app changes.
Leaving this as changes requested because it touches user-data persistence and the current migration path is too broad to run safely as-is; maintainer sign-off is also needed for the data backfill rollout once the script is bounded.
Reviewed by Omi's automated maintainer review (glm-5.2).
by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.
926de2a to
83a8a7c
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_55b3e555-ceeb-40ae-962e-95b17460df2d) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83a8a7cfe6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| elapsed = time.time() - start | ||
| logger.info(f"Done in {elapsed:.1f}s") | ||
| logger.info(f"Results: {total_updates} conversations updated across {users_updated} users.") |
There was a problem hiding this comment.
Report dry-run results as prospective updates
When the migration is invoked with --dry-run, process_user_conversations increments both counters without committing any writes, but this final message still reports that the conversations were "updated." An operator relying on the preview output as rollout evidence could therefore mistake a dry run for a completed migration; label these as conversations that would be updated when args.dry_run is true.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in 8a6c13d: dry-run output reports 'would be updated' instead of 'updated'; asserted in test_dry_run_reports_without_committing.
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the new head and the generated/model default changes are aligned, but I still need to keep this blocked because the production backfill script is not safe enough to run against user conversation data yet, and the branch is still red.
Blocking items:
-
backend/migrations/008_migrate_language_to_en.pystill loads the fulluserscollection into memory (get_all_users()returnslist(users_ref.stream())at lines 36-39), then loads every conversation for each user into memory (conversations = list(conversations_ref.stream())at line 52), and runs 64 users in parallel (line 92). That addresses the intended backfill, but it still has unbounded read/memory/write blast radius and no checkpoint/resume, paging, max-user/max-write guard, or operator throttle beyond--dry-run. Please make the migration bounded and resumable/throttled before this can be run on production user data. -
CI is still failing on this head (
Hygiene, and the current check rollup also shows a failingPR Metadata Preflight). Please get the required hygiene/preflight state green before merge.
File-specific review notes:
backend/models/conversation.py: theConversation,CreateConversation, andExternalIntegrationCreateConversationdefaults now all resolve omittedlanguagetoen. That is consistent with the PR goal, but it changes the meaning of omitted language, so the data rollout and any non-English import/sync paths need maintainer confidence.app/lib/backend/schema/gen/conversation_wire.g.dart: the generated Dart constructor andfromJsonreader now default missinglanguageto"en", matching the backend schema; this looks mechanically consistent with the model change.backend/migrations/008_migrate_language_to_en.py: the migration still filters missing/empty language values correctly, but it needs bounded streaming/paging and operational controls before it is safe for a production Firestore backfill.docs/api-reference/app-client-openapi.json: the two app-client OpenAPI schema entries now documentdefault: "en", matching the backend request/response defaults.docs/api-reference/integration-public-openapi.json: the public integration schema now documents the samedefault: "en"; because external clients may rely on this contract, it should stay in sync with the backend behavior.app/analysis_baseline.json: theprefer_final_fieldsratchet is reduced from 4 to 3, which is a positive cleanup, but CI still needs to be green before merge.
I also checked the prior automated blocking review: the Dart analyzer portion appears addressed, but the Firestore migration safety concern is still present on the current head, so I’m not dismissing the earlier changes-requested review. Leaving this for human maintainer sign-off because this is a user-data backfill/default-semantics change, not just a mechanical generated-schema update.
Reviewed by Omi's automated maintainer review (glm-5.2).
by AI on behalf of David — for maintainer follow-up, please @Git-on-my-level with the specific rollout or data-safety question.
83a8a7c to
eff8ac8
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_5326ca3b-ca26-435b-a913-f65851403c37) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 02fb397539
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| while not max_users or collected < max_users: | ||
| query = db.collection('users').order_by('__name__').limit(page_size) | ||
| if last_id: | ||
| query = query.start_after([last_id]) |
There was a problem hiding this comment.
Pass a document reference to the pagination cursor
When the full migration reaches its second page, or whenever --start-after is supplied, this passes a raw string as the cursor value for order_by('__name__'). Firestore document-ID cursors require a document snapshot/reference (the repository's other paginated queries pass the last snapshot or collection.document(id)), so the production query rejects this cursor even though the fake test accepts it; the migration therefore cannot progress beyond the first page. Use the last snapshot or a document reference in the cursor.
Useful? React with 👍 / 👎.
| for uid in iter_user_ids(db, start_after=args.start_after, page_size=args.page_size, max_users=args.max_users): | ||
| if args.max_writes and total_writes >= args.max_writes: | ||
| logger.info('Reached --max-writes %d, stopping', args.max_writes) | ||
| break | ||
| futures[executor.submit(process_user_conversations, db, uid, args.dry_run)] = uid |
There was a problem hiding this comment.
Enforce --max-writes while work is running
For every invocation with --max-writes, total_writes remains zero throughout this entire scheduling loop because results are not collected until the subsequent as_completed loop. Consequently the limit never stops scheduling, and a staged run such as --max-writes 1000 can update the whole database. Results need to be consumed while scheduling, with the remaining write budget enforced before additional user work is allowed.
Useful? React with 👍 / 👎.
| 'Finished in %.1fs with %d failed user(s); rerun with --start-after %s to resume', | ||
| elapsed, | ||
| failures, | ||
| last_uid, |
There was a problem hiding this comment.
Do not resume after an out-of-order completion
When any worker fails, last_uid is merely the most recently completed successful future, not the greatest contiguous user ID processed before the failure. For example, if u1 fails and u2 completes afterward, the suggested --start-after u2 retry permanently skips u1 while the idempotent migration appears complete. Track a contiguous ordered checkpoint, explicitly retry failed IDs, or advise rerunning without this cursor.
Useful? React with 👍 / 👎.
| if args.max_writes and total_writes >= args.max_writes: | ||
| logger.info('Reached --max-writes %d, stopping', args.max_writes) | ||
| break | ||
| futures[executor.submit(process_user_conversations, db, uid, args.dry_run)] = uid |
There was a problem hiding this comment.
Bound the number of submitted user futures
On the default unlimited full run, this submits one future for every user before collecting any result, and both the executor's unbounded queue and futures retain all of them. The user iterator's paged reads and eight-worker setting therefore do not bound memory; on the repository's 100K-plus user collection, the migration can consume substantial memory or be killed before processing finishes. Keep only a small bounded window of futures in flight and replenish it as each completes.
Useful? React with 👍 / 👎.
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks for the update — this resolves the blockers I had on the earlier heads. I’m leaving this as a positive maintainer signal rather than a formal approval because it still changes a production user-data migration path and should get maintainer sign-off on rollout before merge.
What I checked:
backend/migrations/008_migrate_language_to_en.pynow pages users withiter_user_ids(), lowers/configures concurrency through--workers, supports--max-users,--max-writes,--start-after, and--dry-run, and exits non-zero on per-user failures. That addresses the earlier unbounded Firestore sweep / partial-success concern.backend/models/conversation.pyconsistently defaultsConversation,CreateConversation, andExternalIntegrationCreateConversationlanguage to'en'while still preserving explicitly provided non-English values.backend/utils/sync/pipeline.pynow passes the detected/preferredlanguageintoCreateConversation, so the new default should not silently overwrite non-English sync conversations.backend/tests/unit/test_sync_transcription_prefs.pyadds the important regression case for detected'fr'being persisted on newly synced conversations.backend/tests/unit/test_migrate_language_to_en.pycovers missing/empty backfill behavior, existing-language preservation, dry-run behavior, pagination/resume, max-user bounds, and failure propagation.backend/tests/unit/test_conversation_language_default.pycovers the model default and explicit-language preservation paths.app/lib/backend/schema/gen/conversation_wire.g.dartand the two OpenAPI JSON files mirror the new'en'default for clients/docs.- The ratchet/baseline files (
.github/scripts/product_file_line_count_ratchet_baseline/backend-utils.json,app/analysis_baseline.json) are consistent with the implementation/test churn.
CI is green in the context I reviewed. I’m also dismissing the stale automation change-request reviews from older heads because their specific blockers — unbounded migration shape, failure handling, and red checks — are resolved on this head.
Remaining maintainer note: because this backfills persisted conversation data, please run the migration in a staged rollout (--dry-run, then bounded --max-users / --max-writes, resume from logged user IDs) and confirm that defaulting missing/empty historical language to English is the intended product/data policy before full execution.
Automated maintainer review by glm-5.2 for Omi.
by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.
Resolved on current head: migration is now bounded/resumable, failures exit non-zero, sync language is preserved, and checks are green.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_3b5c7273-3466-42a8-a562-b85185286941) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e72b0bb841
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| uid = next(uid_iter) | ||
| except StopIteration: | ||
| return | ||
| pending[executor.submit(process_user_conversations, db, uid, args.dry_run)] = uid |
There was a problem hiding this comment.
Enforce the write cap inside each worker
When a user has more missing-language conversations than the remaining --max-writes budget, this worker receives no budget and commits every matching conversation before returning; the coordinator checks the limit only afterward. Thus a staged --max-writes 1000 run can perform thousands of writes for one large user, plus writes from other in-flight workers. Fresh evidence on the current head is that the bounded scheduler still calls process_user_conversations without a remaining-write limit, so the earlier post-hoc cap issue remains.
Useful? React with 👍 / 👎.
| if write_budget_exhausted: | ||
| break |
There was a problem hiding this comment.
Drain pending results before reporting success
With --max-writes and multiple workers, reaching the limit breaks out while other futures remain pending; exiting the executor context waits for those workers, so they can still commit, but their results and exceptions are never consumed. If one of those commits fails, failures remains zero and the migration logs Done and exits successfully despite a partial backfill. Fresh evidence on the current head is this new early break, which bypasses the failure-accounting path for all remaining futures.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9170af2448
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| userDefaultsObserver = NotificationCenter.default.addObserver( | ||
| forName: UserDefaults.didChangeNotification, | ||
| object: nil, | ||
| queue: nil | ||
| queue: .main |
There was a problem hiding this comment.
Keep UserDefaults delivery off the main queue
When a background auth commit writes UserDefaults while the main thread is waiting on the session fence, queue: .main synchronously waits for the main thread and recreates the frozen sign-in deadlock fixed by 6467d6fc8. This backend-language commit reverses that fix; retain queue: nil and asynchronously hop to the main actor instead.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| except Exception as e: | ||
| logger.error(f"Error processing {uid}: {e}") |
There was a problem hiding this comment.
Fail when a migration worker update fails
If any Firestore stream or batch commit raises, this handler logs the exception but still reaches Done and exits successfully, allowing automation to record a partially migrated database as complete. Although the earlier thread cites 8a6c13d5e6 as the fix, that commit is not present in this reviewed tree; these catch-and-continue lines are fresh evidence that failures still need to be accumulated and produce a nonzero exit.
Useful? React with 👍 / 👎.
| @@ -286,7 +286,7 @@ class CreateConversation(BaseModel): | |||
| photos: List[ConversationPhoto] = [] | |||
|
|
|||
| source: ConversationSource = ConversationSource.omi | |||
| language: Optional[str] = None | |||
| language: Optional[str] = 'en' | |||
There was a problem hiding this comment.
Pass the resolved sync language into the create model
For a new sync conversation whose detected or explicitly selected language is non-English, process_segment still constructs CreateConversation without language, so this default makes _get_conversation_obj persist en even though processing received the resolved language separately. The prior thread's cited fix 02fb397539 is not an ancestor of this reviewed commit; the unchanged omission at backend/utils/sync/pipeline.py:1149-1158 is fresh evidence that the resolved language must be passed into this model.
Useful? React with 👍 / 👎.
| } | ||
| await _init(); | ||
| runApp(const MyApp()); | ||
| }, (error, stack) => FirebaseCrashlytics.instance.recordError(error, stack, fatal: true)); |
There was a problem hiding this comment.
Guard Crashlytics until Firebase initialization succeeds
If _init() throws before a default Firebase app exists—for example because flavor configuration is missing or invalid—the zone handler calls FirebaseCrashlytics.instance, which itself requires that Firebase app and throws a second error, masking the original startup failure and losing its diagnostics. Restore the Firebase.apps.isNotEmpty guard and a non-Firebase logging fallback rather than reverting the existing startup-error fix in this unrelated backend change.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| while True: | ||
| if await request.is_disconnected(): | ||
| break | ||
| yield f"event: ping\ndata: {{}}\n\n" | ||
| await asyncio.sleep(30) |
There was a problem hiding this comment.
Return 405 for idle MCP GET streams
Every MCP client that opens this GET now occupies a Cloud Run request slot in an infinite ping loop until disconnect or the one-hour request timeout, despite the endpoint carrying no protocol messages. This directly reverses the parent commit's production fix after roughly 1,200 concurrent parked streams exhausted container concurrency and pushed MCP tool-call latency into minutes; keep the stateless transport's 405 Method Not Allowed response instead.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| }) async { | ||
| Logger.debug('initiateWebsocket in capture_provider'); |
There was a problem hiding this comment.
Deduplicate concurrent transcription socket attempts
When the 15-second keep-alive tick fires while an earlier _initiateWebsocket call is still connecting, this implementation starts another identical attempt; the socket pool serializes but does not deduplicate them, so both can eventually open /v4/listen sessions and race the controller and UI state. Restore the per-configuration in-flight guard removed by this unrelated rollback while continuing to allow forced or differently configured attempts.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| Log.d(TAG, "startService($caller): service running, forcing reconnect for $deviceAddress") | ||
| inst.forceReconnect(deviceAddress, requiresBond, caller) | ||
| return |
There was a problem hiding this comment.
Re-emit device-ready for an existing Android BLE link
When Background Mode keeps the service and GATT connection alive after the Flutter engine dies, the next app launch routes its connect request to forceReconnect, which immediately returns for an already-connected peripheral and never emits Dart's only onDeviceReady signal. The app consequently waits through the connection timeout and reports the device disconnected despite the live link, disabling transcription until a manual disconnect; route this through the adopt-and-resync path restored by the reverted Android fix.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| MEMORY_V3_GET_ENABLED: | ||
| value: 'false' | ||
| # Canonical graph and /v3/memories first-page cursors fail closed without this HMAC. | ||
| MEMORY_V3_CURSOR_SECRET: | ||
| secret: | ||
| name: prod-omi-backend-secrets | ||
| key: MEMORY_V3_CURSOR_SECRET | ||
| MCP_OAUTH_CLIENTS_JSON: |
There was a problem hiding this comment.
Preserve the production memory cursor secret binding
On the next production Cloud Run or GKE deployment, this overlay no longer injects MEMORY_V3_CURSOR_SECRET, even though /v1/knowledge-graph and signed canonical-memory cursors fail closed when the HMAC secret is absent. Production was already repaired to consume this secret, so deploying this tree strips the live binding and makes Mind Map and cursor-backed reads return missing_cursor_secret; restore the secret and version entries in every production serving target.
AGENTS.md reference: backend/AGENTS.md:L171-L173
Useful? React with 👍 / 👎.
| final permission = await Geolocator.checkPermission(); | ||
| if (permission == LocationPermission.always || permission == LocationPermission.whileInUse) { | ||
| await ForegroundUtil.initializeForegroundService(); | ||
| await ForegroundUtil.startForegroundTask(); | ||
| } |
There was a problem hiding this comment.
Do not start foreground audio from location permission
For every mobile user who has granted location permission, opening Home now starts flutter_foreground_task even when no capture is active. On iOS this holds AVAudioSession and leaves the green microphone indicator and foreground service running while idle, producing the all-day battery drain fixed by b5b77f5fa; foreground audio ownership must instead follow an active capture with recent frames.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| // Proactive notifications are now OFF by default for everyone. Run the one-time | ||
| // migration before any assistant can fire, so existing users are flipped to Off | ||
| // once (they can re-enable in Settings). | ||
| NotificationService.migrateToOffByDefaultIfNeeded() |
There was a problem hiding this comment.
Keep proactive notifications at the Balanced default
This launch migration writes frequency 0 locally and to the backend for every install that has not previously run the old off-by-default migration, disabling proactive notifications for both existing users and fresh installs. It reverses the shipped Balanced-default migration, which preserves explicit opt-in levels and only enables the default-on Live Suggestions and Insight categories; call migrateToBalancedDefaultIfNeeded so a backend-language change does not silently opt the user base out again.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
9170af2 to
e72b0bb
Compare
|
Note: the branch briefly carried a commit (9170af2) that reverted ~1281 files of recent |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 669c7deebe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -85,7 +56,7 @@ class ProductMemorySearchResponse(BaseModel): | |||
|
|
|||
| uid: str = Field(description='Authenticated user id.') | |||
| query: str = Field(description='Search query string.') | |||
| items: List[ProductMemorySearchItem] = Field(description='Default-visible memory rows for the current page.') | |||
| items: List[MemoryItem] = Field(description='Default-visible memory items for the current page.') | |||
There was a problem hiding this comment.
Restore the product-memory projection response type
For every populated /memory/search or /memory/archive/search response, the read seams return projection rows containing fields such as memory_id, lifecycle_status, and date, not full MemoryItem records with required fields such as version, uid, status, and timestamps. FastAPI therefore fails response validation and returns 500 whenever either search finds a result, while misleadingly allowing empty pages through; keep these two responses typed to the projection model and reserve MemoryItem for the vector route that actually emits it.
Useful? React with 👍 / 👎.
| @@ -350,7 +350,6 @@ async def send_onboarding(event: Dict[str, Any]) -> None: | |||
| await request.websocket.send_json(event) | |||
|
|
|||
| self.onboarding_handler = OnboardingHandler(request.uid, send_onboarding, self.transcripts.enqueue) | |||
There was a problem hiding this comment.
Send the initial speech-profile onboarding question
When onboarding_mode starts, this now only constructs the handler and never invokes send_current_question; there is also no remaining start_onboarding receiver path in this tree. Because answer and skip handling cannot run before question zero is delivered, both onboarding and Settings speech-profile sessions remain on an empty question screen at 0% indefinitely despite the socket being active.
Useful? React with 👍 / 👎.
| try await ActionItemStorage.shared.deleteActionItemByBackendId( | ||
| task.id, | ||
| deletedBy: "user", | ||
| authorization: Self.localMutationAuthorization( | ||
| snapshot: lease.authorizationSnapshot | ||
| ) | ||
| } | ||
| ) |
There was a problem hiding this comment.
Retain a tombstone until task deletion is acknowledged
When a synced task is deleted while offline or the backend DELETE fails, this call hard-deletes the only local record before the request is attempted, and the catch path merely logs the failure. A later cloud hydration consequently sees the still-present backend row with no pending tombstone and re-inserts the task, so user-deleted tasks resurrect; mark the row deleted/unsynced and retry until the backend acknowledges it instead. This stale rollback also removes the behavioral coverage for that contract.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| @@ -916,28 +916,17 @@ async def get_desktop_appcast_xml( | |||
| async def download_latest_desktop_release( | |||
| platform: str = Query(default="macos", pattern="^(macos|windows|linux)$"), | |||
| channel: str = Query(default="stable", pattern="^(beta|stable)$"), | |||
| identity: Optional[str] = Query(default=None, pattern="^(stable|beta)$"), | |||
| identity: str = Query(default="stable", pattern="^(stable|beta)$"), | |||
There was a problem hiding this comment.
Default beta-channel downloads to the beta identity
The public macos.omi.me/beta redirect calls /v2/desktop/download/latest?channel=beta without an identity parameter, so this new default selects the generic stable-identity DMG from the beta release rather than the separately installable Omi Beta artifact. Users following the public beta link therefore install the production bundle identity and production services instead of the isolated com.omi.computer-macos.beta build; when identity is omitted, derive it from the requested channel.
Useful? React with 👍 / 👎.
| func startMicrophoneAudioCapture() async { | ||
| guard let audioCaptureService = audioCaptureService else { return } | ||
|
|
||
| // Authorization first, capture second. CoreAudio HAL capture never triggers the | ||
| // system microphone prompt on its own: with a notDetermined or revoked TCC entry it | ||
| // "succeeds" and delivers zero samples forever. The silent-mic watchdog then reads | ||
| // those zeros as a dead device and loops the user through rebuilds into a | ||
| // "Microphone Isn't Capturing Audio" alert every ~90s — a permission problem wearing | ||
| // a hardware costume. startTranscription() has its own guard, but resume, the meeting | ||
| // gate, and the watchdog's own rebuild all arm capture through here without passing it. | ||
| var gateAction = MicrophoneCaptureAuthorizationPolicy.action( | ||
| for: AudioCaptureService.authorizationStatus()) | ||
| if gateAction == .requestPermission { | ||
| log("Transcription: microphone permission undetermined — requesting before capture") | ||
| gateAction = MicrophoneCaptureAuthorizationPolicy.action( | ||
| afterRequestGranted: await AudioCaptureService.requestPermission()) | ||
| } | ||
| guard gateAction == .proceed else { | ||
| surfaceMicrophonePermissionAlert() | ||
| stopTranscription() | ||
| return | ||
| } | ||
|
|
||
| configureSharedCaptureWatchdog(audioCaptureService) |
There was a problem hiding this comment.
Gate shared microphone capture on TCC authorization
When microphone permission is denied, revoked, or still undetermined, resume, meeting-gate, and recovery paths can enter this method without passing through the separate startTranscription permission check. CoreAudio HAL then appears to start but supplies zero samples, causing repeated capture rebuilds followed by a misleading hardware-failure alert instead of prompting for or directing the user to microphone permission; check authorization here before arming the shared capture stack. This stale rollback also removes the policy and regression tests for the non-primary entry paths.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| } finally { | ||
| isSearching = false; | ||
| notifyListeners(); | ||
|
|
||
| String? _selectedCapabilityId() { | ||
| final capability = filters['Capabilities']; | ||
| return capability is AppCapability ? capability.id : null; | ||
| if (_pendingSearchQuery != queryBeingSearched) { | ||
| performServerSearch(); | ||
| } |
There was a problem hiding this comment.
Keep search state active while draining the latest query
When the user changes an Apps query while the previous request is in flight, the pending query is noticed here, but isSearching is first cleared and listeners are notified before the replacement request starts. The Apps page consequently renders the old or empty results as “No apps found” for at least one frame even though the latest search is still pending; filter-only changes with unchanged text are worse because the string comparison does not queue a replacement at all. Track search intent by revision and keep one draining operation in the searching state until the newest request settles.
Useful? React with 👍 / 👎.
| def upload(file_path: Union[str, Path]) -> Dict[str, Any]: | ||
| _record_direct_file_chat_surface() | ||
| _assert_direct_file_chat_allowed() |
There was a problem hiding this comment.
Allow the acknowledged direct file-chat surface
In the production runtime, OMI_LLM_GATEWAY_FEATURE_MODE is gateway while OMI_LLM_GATEWAY_ALLOW_DIRECT_MODEL_EXCEPTION is false, so this guard raises GatewayDirectModelSurfaceBlocked before every file or image upload reaches OpenAI. File chat has no gateway implementation because Files, Assistants, and vision are direct-only surfaces; record this acknowledged exception and allow it rather than making all attachment uploads fail in production.
Useful? React with 👍 / 👎.
| @@ -218,7 +160,7 @@ def vad_is_empty( | |||
| try: | |||
| with open(file_path, 'rb') as file: | |||
| files = {'file': (file_path.split('/')[-1], file, 'audio/wav')} | |||
| response = requests.post(hosted_vad_url, files=files, timeout=_hosted_vad_timeout_seconds()) | |||
| response = requests.post(hosted_vad_url, files=files, timeout=300) | |||
There was a problem hiding this comment.
Bound hosted VAD deadlines before local fallback
When HOSTED_VAD_API_URL accepts a connection but stalls, each synchronous conversation-processing call now occupies its worker for as long as five minutes before the existing local ONNX fallback can run. A hosted VAD degradation can therefore leave processing cards hanging and exhaust the bounded worker pool across otherwise healthy requests; use separate short connect/read deadlines, with the read deadline capped well below this value, so the fallback remains operational.
Useful? React with 👍 / 👎.
669c7de to
47c6bba
Compare
|
Rebuilt the branch cleanly on current |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_81c55c48-a21f-408d-a47e-0ac1ede0e47a) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bdf321d264
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if let continuation = handle.continuation { | ||
| handle.continuation = nil | ||
| continuation.resume(returning: .cancelled) |
There was a problem hiding this comment.
Serialize cancellation with the gate handoff
When a queued chat-context task is cancelled after release() takes the slot continuation but before it resumes it, this cancellation handler can still read the same continuation from handle.continuation; it resumes .cancelled, and release() then resumes .granted, causing a checked-continuation double-resume trap that can crash desktop chat. Keep a single synchronized continuation owner across cancellation and grant handoff.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| return firestore.Client(credentials=credentials, project=project_id) | ||
|
|
||
| prepare_google_credentials() | ||
| return firestore.Client() |
There was a problem hiding this comment.
Pin Firestore to the customer service-account project
In the checked backend-listen dev deployment, SERVICE_ACCOUNT_JSON identifies the customer project while GOOGLE_CLOUD_PROJECT is explicitly based-hardware-dev; constructing firestore.Client() without the service account's explicit project_id therefore selects the compute project and makes user, subscription, and usage reads hit shadow or missing documents. Restore the explicit credentials/project binding instead of relying on default project resolution.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| if ( | ||
| aseg.duration_seconds < 10 | ||
| ): # TODO: validate duration more accurately, segment.last.end - segment.first.start - 10 |
There was a problem hiding this comment.
Validate uploaded audio against the transcript span
When an upload is longer than ten seconds but substantially shorter than its conversation transcript—for example, 14 seconds of audio for segments spanning 25 seconds—this fixed threshold accepts the truncated file and starts post-processing it as complete. That produces post-processing output from incomplete audio rather than cancelling the bad upload; retain the transcript-derived minimum-duration check.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| } finally { | ||
| if (succeeded && options?.protectPinnedBindingAfterWork) { | ||
| this.protectPinnedBinding(worker.idlePinnedBindingId); |
There was a problem hiding this comment.
Recycle pi-mono workers before draining queued sends
When a pi-mono execution throws after dispatch, this finally block immediately drains queued leases without marking the process-local worker unhealthy, removing it from the pool, or invalidating its pinned binding. The next chat send can therefore reacquire the same poisoned worker and fail repeatedly until the agent daemon is restarted; recycle the failed worker before making queued sends runnable.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| conversations = _filterPendingDeletes(result.items); | ||
|
|
||
| // processing convos | ||
| processingConversations = conversations.where((m) => m.status == ConversationStatus.processing).toList(); | ||
|
|
||
| // completed convos | ||
| conversations = conversations.where((m) => m.status == ConversationStatus.completed).toList(); |
There was a problem hiding this comment.
Preserve websocket completions across stale list refreshes
When a conversation completes over the websocket while fetchConversations() is awaiting its list request, a stale response that still labels the row as processing reaches these assignments afterward: it recreates the Processing card and filters the live completed row out of conversations. The user then sees a completed conversation revert to Processing until a later authoritative refresh; reconcile the response against websocket revisions instead of replacing both lists wholesale.
AGENTS.md reference: AGENTS.md:L50-L52
Useful? React with 👍 / 👎.
| // Cheap early exits before resolving the active window. | ||
| let idleSeconds = systemIdleSeconds() | ||
| if idleSeconds >= captureTrigger.idleThreshold { | ||
| logCaptureGate("idle") | ||
| return |
There was a problem hiding this comment.
Exempt active media playback from the HID idle gate
When a user watches media without keyboard or mouse input past the idle threshold, browsers and video players keep the display awake but systemIdleSeconds() still exceeds the threshold, so this return stops all proactive captures and nudges for the remainder of playback. Restore the power-management assertion check so active media viewing is treated as presence rather than absence.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| guard let window else { return } | ||
| attachedWindow = window | ||
| reassertIfNeeded(force: true) | ||
| // The transparent shell must pass clicks on its dead margins through to whatever is behind | ||
| // the window — see `ShellClickThrough.swift`. | ||
| mouseInterceptionSync = ShellMouseInterceptionSync(window: window) | ||
| updateObserver = NotificationCenter.default.addObserver( |
There was a problem hiding this comment.
Pass clicks through transparent shell margins
The shell NSWindow is larger than the visible glass panels it contains, but attaching it here no longer installs any window-level mouse-interception sync. AppKit therefore treats transparent title-band, margin, and inter-panel space as part of Omi's window, swallowing clicks intended for applications underneath and preventing those apps from activating; toggle ignoresMouseEvents over non-content regions while retaining interactive resize and modal regions.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
| self.isOpaque = false | ||
| self.backgroundColor = .clear | ||
| self.hasShadow = false | ||
| // NSPanel defaults hidesOnDeactivate to true, which orders the notch out | ||
| // when another app activates. isFloatingPanel is the overlay companion; | ||
| // re-assert always-on-top after it so AppKit cannot drop us to .floating. | ||
| self.isFloatingPanel = true | ||
| self.hidesOnDeactivate = false | ||
| self.level = Self.alwaysOnTopLevel | ||
| self.collectionBehavior = Self.overlayCollectionBehavior | ||
| self.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary] |
There was a problem hiding this comment.
Keep the floating panel visible when Omi deactivates
After the floating bar is shown, activating another application deactivates this NSPanel; without overriding the panel default hidesOnDeactivate behavior, AppKit orders the notch/bar out, and the removed durable-visibility recovery means it may not return until the user invokes Push-to-Talk. Configure it as a non-hiding floating overlay and reassert that presentation contract when ordering it forward.
AGENTS.md reference: desktop/macos/AGENTS.md:L356-L359
Useful? React with 👍 / 👎.
Rebuild of PR branch on current origin/main. The prior head carried an accidental revert commit reverting ~1281 files of main; this branch contains only the intended feature diff (9 files). Defaults Conversation, CreateConversation, and ExternalIntegrationCreateConversation language to 'en', preserving explicit non-English values; sync pipeline threads the detected/preferred language into CreateConversation; resumable bounded backfill migration (008) pages users, supports --max-users/--max-writes/--start-after/ --dry-run/--workers, and exits non-zero on per-user failures. Tests: 81 passed.
2a0977e to
d459537
Compare
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_366677c4-376d-4daa-b76f-8e9d0d44b869) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d459537faa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| logger.info( | ||
| 'Results: %d conversations %s across %d users (%d writes).', total_updates, verb, users_processed, total_writes | ||
| ) |
There was a problem hiding this comment.
Log the cursor needed to continue staged runs
After a successful --max-users stage, the only output is aggregate counts, even though the documented resume procedure requires the last processed UID. Re-running the same staged command without a usable --start-after value just processes the same first users again, so operators cannot advance through the migration using the documented workflow; emit a correctly ordered resume cursor in the success summary.
Useful? React with 👍 / 👎.
Migrate conversation language field default to 'en'
Defaults
Conversation,CreateConversation, andExternalIntegrationCreateConversationlanguage to'en', preserving explicit non-English values. The sync pipeline threads the detected/preferred language intoCreateConversation. Adds a bounded, resumable backfill migration (backend/migrations/008_migrate_language_to_en.py) that pages users, supports--max-users/--max-writes/--start-after/--dry-run/--workers, and exits non-zero on per-user failures.Tests: 81 passed.
Line-Count-Exception: backend/utils/sync/pipeline.py | 2499 -> 2500 | threads the resolved detected language into CreateConversation so sync conversations persist the actual language instead of the 'en' default